package cn.kennylee.codehub.mq.lip.integration.base;

import cn.kennylee.codehub.mq.lip.integration.base.anno.IntegrationMqConsumer;
import cn.kennylee.codehub.mq.lip.integration.base.anno.MqListenerGenerator;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.NonNull;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * IntegrationMqConsumer注解处理器，生成消费者代码
 * <p>Created on 2025/4/18.</p>
 *
 * @author kennylee
 * @since 0.0.1
 */
@Slf4j
@NoArgsConstructor
public class IntegrationMqConsumerAnnoProcessor implements BeanPostProcessor, ApplicationContextAware {

    private final Map<IntegrationMqConsumer.MqType, MqListenerGenerator> generatorMap = new HashMap<>();
    private ConfigurableApplicationContext applicationContext;

    /**
     * 添加消费者生成器
     *
     * @param mqType    MQ类型
     * @param generator 消费者生成器
     */
    public void addGenerator(IntegrationMqConsumer.MqType mqType, MqListenerGenerator generator) {
        generatorMap.put(mqType, generator);
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext context) throws BeansException {
        this.applicationContext = (ConfigurableApplicationContext) context;
    }

    /**
     * BeanPostProcessor的后置处理方法，在Bean实例化后执行
     *
     * @param bean     the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one; never {@code null}
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, @NonNull String beanName) throws BeansException {
        // 只支持单例Bean，否则会重复注册
        if (!applicationContext.containsBean(beanName) ||
            !applicationContext.isSingleton(beanName)) {
            return bean;
        }

        Class<?> targetClass = getTargetClass(bean);
        if (bean.getClass() != targetClass) {
            log.debug("Bean '{}' 是代理对象，原始类: {}", beanName, targetClass.getName());
        }

        for (Method method : targetClass.getDeclaredMethods()) {
            IntegrationMqConsumer annotation = method.getAnnotation(IntegrationMqConsumer.class);
            if (Objects.nonNull(annotation)) {
                if (log.isDebugEnabled()) {
                    log.debug("找到MQ注解：{}，方法：{}，BeanName：{}", annotation, method.getName(), beanName);
                }
                MqListenerGenerator generator = generatorMap.get(annotation.type());
                if (generator == null) {
                    throw new UnsupportedOperationException("Unsupported MQ type: " + annotation.type());
                }

                AbstractMqListener<?> listener = generator.generateListener(bean, method, annotation);

                // 手动注册 listener Bean
                String listenerBeanName = generateListenerBeanName(bean, method);
                registerSingletonBean(listenerBeanName, listener);
            }
        }
        return bean;
    }

    /**
     * 获取目标对象的类
     *
     * @param bean 对象
     * @return 目标对象的类
     */
    public static Class<?> getTargetClass(Object bean) {
        // 判断是否被代理（CGLIB 或 JDK 动态代理）
        Class<?> targetClass = bean.getClass();
        if (AopUtils.isAopProxy(bean)) {
            // 获取原始类
            targetClass = AopUtils.getTargetClass(bean);
        }
        return targetClass;
    }

    private void registerSingletonBean(String name, Object bean) {
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();

        log.info("通过注解，生成MQ消费者类：{}，加载到Spring上下文，BeanName：{}", getTargetClass(bean).getSimpleName(), name);

        // 注册 singleton，允许后续被其他 BeanPostProcessor 处理（AOP、注解等）
        beanFactory.registerSingleton(name, bean);

        // 触发 postProcessAfterInitialization（如果其他 BeanPostProcessor 已经注册）
        if (beanFactory instanceof AbstractAutowireCapableBeanFactory abstractAutowireCapableBeanFactory) {
            abstractAutowireCapableBeanFactory.initializeBean(bean, name);
        }
    }

    /**
     * 生成消费者Bean名称
     *
     * @param bean   对象
     * @param method 注解方法
     * @return 生成的消费者Bean名称
     */
    public static String generateListenerBeanName(Object bean, Method method) {
        return getTargetClass(bean).getSimpleName() + "_" + method.getName() + "_MqConsumer";
    }

    /**
     * 生成消费者类名
     *
     * @param targetBean   对象
     * @param targetMethod 注解方法
     * @return 生成的消费者类名
     */
    @NonNull
    public static String generateClassName(Object targetBean, Method targetMethod) {
        return getTargetClass(targetBean).getName() + "$" + targetMethod.getName() + "Consumer";
    }
}

